﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Management;
using System.Text;
using System.Threading;

namespace ComputerConfigurationCollectorLibrary
{
	public class Collector
	{
		private const string COLUMN_NAME_COMPUTER_NAME = "Computer Name";
		private const string COLUMN_NAME_ERROR = "Error";
		private const string COLUMN_NAME_EXCEPTION_TYPE = "Exception Type";
		private const double MAX_WMI_QUERY_DURATION_IN_SECONDS = 30;
		private const int MAX_WMI_QUERY_RESULTS = 20;
		private long _maxConcurrency = 10;
		private WorkItemQueue _concurrencyQueue;

		private object _syncThreadAccessToAggregateTables = new object();

		private ConnectionOptions _connectionOptions = new ConnectionOptions();
		public ConnectionOptions ConnectionOptions
		{
			get { return _connectionOptions; }
			set { _connectionOptions = value; }
		}

		private ObjectGetOptions _objectGetOptions = new ObjectGetOptions();
		public ObjectGetOptions ObjectGetOptions
		{
			get { return _objectGetOptions; }
			set { _objectGetOptions = value; }
		}

		private EnumerationOptions _enumerationOptions = new EnumerationOptions();
		public EnumerationOptions EnumerationOptions
		{
			get { return _enumerationOptions; }
			set { _enumerationOptions = value; }
		}

		#region Public Methods
		/// <summary>
		/// Initialize the class.  Sets default timeouts for the WMI options.
		/// </summary>
		public Collector()
		{
			_connectionOptions.Timeout = TimeSpan.FromSeconds(MAX_WMI_QUERY_DURATION_IN_SECONDS);
			_objectGetOptions.Timeout = TimeSpan.FromSeconds(MAX_WMI_QUERY_DURATION_IN_SECONDS);
			_enumerationOptions.Timeout = TimeSpan.FromSeconds(MAX_WMI_QUERY_DURATION_IN_SECONDS);
			_objectGetOptions.UseAmendedQualifiers = true;
			_concurrencyQueue = new WorkItemQueue(_maxConcurrency);
		}

		/// <summary>
		/// Given a list of computers, iterate through the WMI namespaces on all of the computers and build a list of all known WMI namespaces
		/// </summary>
		/// <param name="targetComputers">List of computers to query.  Accepts either short name, fqdn, or IP Address.</param>
		/// <returns>List of WMI namespaces from all servers queried.</returns>
		public List<string> GetWmiNamespaces(List<string> targetComputers)
		{
			List<string> wmiNamespaces = new List<string>();
			foreach (string targetComputer in targetComputers)
			{
				object[] state = { targetComputer, wmiNamespaces };
				_concurrencyQueue.EnqueueWorkItem(new WaitCallback(getWmiNamespacesThreaded), state);
			}
			_concurrencyQueue.WaitAllWorkItems();
			wmiNamespaces.Sort();

			if (wmiNamespaces.Count == 0)
			{
				wmiNamespaces = null;
			}
			return wmiNamespaces;
		}

		/// <summary>
		/// Given a list of computers and a specific namespace, enumerate all WMI classes in the namespace.
		/// </summary>
		/// <param name="targetComputers">List of computers to query.  Accepts either short name, fqdn, or IP Address.</param>
		/// <param name="wmiNamespaceName">WMI namespace to collect the class list from.</param>
		/// <returns>List of WMI classes in the specified namespace from all servers queried.</returns>
		public List<string> GetWmiClasses(List<string> targetComputers, string wmiNamespaceName)
		{
			//TODO:  Multi-thread
			List<string> wmiClasses = new List<string>();
			foreach (string computer in targetComputers)
			{
				foreach (string wmiClass in this.getWmiClasses(computer, wmiNamespaceName))
				{
					if (!wmiClasses.Contains(wmiClass))
					{
						wmiClasses.Add(wmiClass);
					}
				}
			}

			return wmiClasses;
		}

		/// <summary>
		/// Given a list of computers, a specific namespace, and a class enumerate all properies in the class.
		/// </summary>
		/// <param name="targetComputers">List of computers to query.  Accepts either short name, fqdn, or IP Address.</param>
		/// <param name="wmiNamespaceName">WMI namespace the class resides in.</param>
		/// <param name="wmiClassName">WMI class name to collect the properties of.</param>
		/// <returns>List of all properties in the WMI class specified.</returns>
		public List<string> GetWmiClassProperties(List<string> targetComputers, string wmiNamespaceName, string wmiClassName)
		{
			//TODO: Multi-Thread
			List<string> wmiClassProperties = new List<string>();
			foreach (string targetComputer in targetComputers)
			{
				foreach (string wmiClassProperty in this.getWmiClassProperties(targetComputer, wmiNamespaceName, wmiClassName))
				{
					if (!wmiClassProperties.Contains(wmiClassProperty))
					{
						wmiClassProperties.Add(wmiClassProperty);
					}
				}
			}

			return wmiClassProperties;
		}

		/// <summary>
		/// Given a list of computers, a specific namespace, and a class enumerate all properies in the class.
		/// </summary>
		/// <param name="targetComputers">List of computers to query.  Accepts either short name, fqdn, or IP Address.</param>
		/// <param name="wmiNamespaceName">WMI namespace the class resides in.</param>
		/// <param name="wmiClassName">WMI class name to collect the properties of.</param>
		/// <returns>DataTable of all properties in the WMI class specified and the corresponding data type of the property.</returns>
		public DataTable GetWmiClassPropertiesAndDataTypes(List<string> targetComputers, string wmiNamespaceName, string wmiClassName)
		{
			//TODO:  Add in a column to describe if it is of type Array.
			DataTable aggregatedResults = new DataTable();
			foreach (string targetcomputer in targetComputers)
			{
				DataTable results = getWmiClassPropertiesAndDataTypes(targetcomputer, wmiNamespaceName, wmiClassName);
				if (aggregatedResults.Columns.Count < 1)
				{
					foreach (DataColumn dc in aggregatedResults.Columns)
					{
						aggregatedResults.Columns.Add(dc.ColumnName, dc.DataType);
					}
				}

				foreach (DataRow dr in results.Rows)
				{
					aggregatedResults.Rows.Add(dr);
				}
			}

			return aggregatedResults;
		}

		/// <summary>
		/// Given a list of computers, a specific namespace, a class, and a list of properties, get all results.
		/// </summary>
		/// <param name="targetComputers">List of computers to query.  Accepts either short name, fqdn, or IP Address.</param>
		/// <param name="wmiNamespaceName">WMI namespace the class resides in.</param>
		/// <param name="wmiClassName">WMI class name the properties reside in.</param>
		/// <param name="wmiClassProperties">The list of properties desired for each result.</param>
		/// <returns>DataTable of all results and the properites for each result.</returns>
		public DataTable GetWmiData(List<string> targetComputers, string wmiNamespaceName, string wmiClassName, List<string> wmiClassProperties)
		{
			string wQLQuery = this.buildWqlQuery(wmiClassName, wmiClassProperties);
			return GetWmiData(targetComputers, wmiNamespaceName, wQLQuery);
		}
		/// <summary>
		/// Given a list of computers, a specific namespace, and a WMI query returns the result set in a DataTable format.
		/// </summary>
		/// <param name="targetComputers">List of computers to query.  Accepts either short name, fqdn, or IP Address.</param>
		/// <param name="wmiNamespaceName">WMI namespace the class resides in.</param>
		/// <param name="wmiQueryLanguage">Standard WQL syntax.  For details on how to construct this, reference:<para>http://msdn.microsoft.com/en-us/library/aa392902.aspx</para><para>http://msdn.microsoft.com/en-us/library/aa394606.aspx</para></param>
		/// <returns>DataTable of all results and the properites for each result.</returns>
		public DataTable GetWmiData(List<string> targetComputers, string wmiNamespaceName, string wmiQueryLanguage)
		{
			DataTable aggregatedResults = new DataTable();

			foreach (string targetComputer in targetComputers)
			{
				object[] state = { targetComputer, wmiNamespaceName, wmiQueryLanguage, aggregatedResults };
				_concurrencyQueue.EnqueueWorkItem(new WaitCallback(getWmiDataThreaded), state);
				//DataTable results = this.getWmiData(targetcomputer, wmiNamespaceName, wmiQueryLanguage);
			}

			_concurrencyQueue.WaitAllWorkItems();

			//translate back into the pretty name
			foreach (DataColumn dc in aggregatedResults.Columns)
			{
				aggregatedResults.Columns[dc.ColumnName].ColumnName = aggregatedResults.Columns[dc.ColumnName].Caption;
				aggregatedResults.Columns[dc.ColumnName].Caption = aggregatedResults.Columns[dc.ColumnName].DataType.ToString();
			}

			return aggregatedResults;
		}
		#endregion

		#region Helper methods for threading.
		private void getWmiNamespacesThreaded(object stateInfo)
		{
			string targetComputer = (string)(((object[])stateInfo)[0]);
			List<string> wmiNamespaces = (List<string>)(((object[])stateInfo)[1]);

			List<string> results = this.getWmiNamespaces(targetComputer);

			//Merge lists into one master list.  Keep upper case to ensure consistent string matching
			lock (_syncThreadAccessToAggregateTables)
			{
				foreach (string s in results)
				{
					if (!wmiNamespaces.Contains(s.ToUpperInvariant()))
					{
						wmiNamespaces.Add(s.ToUpperInvariant());
					}
				}
			}
		}

		private void getWmiDataThreaded(object stateInfo)
		{
			string targetComputer = (string)(((object[])stateInfo)[0]);
			string wmiNamespaceName = (string)((object[])stateInfo)[1];
			string wmiQueryLanguage = (string)((object[])stateInfo)[2];
			DataTable aggregatedResults = (DataTable)((object[])stateInfo)[3];
			DataTable result = this.getWmiData(targetComputer, wmiNamespaceName, wmiQueryLanguage);

			lock (_syncThreadAccessToAggregateTables)
			{
				//Check to ensure all columns exist in the aggregate table
				foreach (DataColumn dc in result.Columns)
				{
					if (aggregatedResults.Columns[dc.ColumnName] == null)
					{
						aggregatedResults.Columns.Add(dc.ColumnName, dc.DataType);
						aggregatedResults.Columns[dc.ColumnName].Caption = result.Columns[dc.ColumnName].Caption;
					}
				}

				foreach (DataRow dr in result.Rows)
				{
					aggregatedResults.ImportRow(dr);
				}
			}
		}
		#endregion

		#region Private Methods
		private ManagementScope getManagementScope(
			string targetComputer
			, string wmiNamespaceName
			, out Exception error)
		{
			error = null;
			ManagementScope ms = null;

			if (!string.IsNullOrEmpty(targetComputer) || !string.IsNullOrEmpty(wmiNamespaceName))
			{
				ms = new ManagementScope("\\\\" + targetComputer + "\\" + wmiNamespaceName, _connectionOptions);

				if (!ms.IsConnected)
				{
					try
					{
						ms.Connect();
					}
					catch (ManagementException ex)
					{
						error = ex;
						ms = null;
					}
					catch (UnauthorizedAccessException ex)
					{
						error = ex;
					}
					catch (System.Runtime.InteropServices.COMException ex)
					{
						error = ex;
						ms = null;
					}
				}
			}
			return ms;
		}

		private ManagementObjectCollection getClassInformation(
			string targetComputer
			, string wmiNamespace
			, string path
			, out Exception error)
		{
			error = null;
			ManagementScope currentManagementScope = getManagementScope(targetComputer, wmiNamespace, out error);
			ManagementObjectCollection results = null;

			if (currentManagementScope != null)
			{
				ManagementClass nsClass = new ManagementClass(currentManagementScope
					, new ManagementPath(path)
					, _objectGetOptions);

				try
				{
					results = nsClass.GetInstances();
				}
				catch (ManagementException ex)
				{
					error = ex;
				}
				catch (UnauthorizedAccessException ex)
				{
					error = ex;
				}
				catch (System.Runtime.InteropServices.COMException ex)
				{
					error = ex;
				}
			}

			return results;
		}

		private ManagementObjectCollection getSearchResults(
			string targetComputer
			, string wmiNamespace
			, string wmiQuery
			, out Exception error)
		{
			error = null;
			ManagementScope currentManagementScope = getManagementScope(targetComputer, wmiNamespace, out error);

			ManagementObjectCollection results = null;

			if (currentManagementScope != null)
			{
				ObjectQuery oq = new ObjectQuery(wmiQuery);

				ManagementObjectSearcher searcher =
					new ManagementObjectSearcher(currentManagementScope, oq, _enumerationOptions);

				try
				{
					results = searcher.Get();
					//Actually pulls the data, test here to see if we can communicate
					foreach (ManagementObject mo in results)
					{
						break;
					}
				}
				catch (ManagementException ex)
				{
					error = ex;
					results = null;
				}
				catch (UnauthorizedAccessException ex)
				{
					error = ex;
					results = null;
				}
				catch (System.Runtime.InteropServices.COMException ex)
				{
					error = ex;
					results = null;
				}
				finally
				{
					searcher.Dispose();
				}
			}

			return results;
		}

		private ManagementObject getSpecificObject(
			string wmiPath
			, out Exception error)
		{
			error = null;

			ManagementObject mo = new ManagementObject(wmiPath, _objectGetOptions);

			try
			{
				//mo.GetRelated();
				mo.Get();
			}
			catch (ManagementException ex)
			{
				error = ex;
			}
			catch (UnauthorizedAccessException ex)
			{
				error = ex;
			}
			catch (System.Runtime.InteropServices.COMException ex)
			{
				error = ex;
			}

			return mo;
		}

		private List<string> getWmiNamespaces(string targetComputer)
		{
			List<string> wmiNameSpaces = new List<string>();
			this.getChildNamespaces(targetComputer, "root", ref wmiNameSpaces);
			return wmiNameSpaces;
		}

		private void getChildNamespaces(
			string targetComputer
			, string parentNamespace
			, ref List<string> wmiNamespaces)
		{
			Exception error = null;
			ManagementObjectCollection results =
				this.getClassInformation(targetComputer, parentNamespace, "__namespace", out error);

			if (results != null)
			{
				foreach (ManagementObject ns in results)
				{
					// Add namespaces to the list.
					string namespaceName = parentNamespace + "\\" + ns["Name"].ToString();
					wmiNamespaces.Add(namespaceName);
					getChildNamespaces(targetComputer, namespaceName, ref wmiNamespaces);
				}
			}
		}

		private List<string> getWmiClasses(
			string targetComputer
			, string wmiNamespaceName)
		{
			List<string> listOfClasses = null;
			Exception error = null;
			ManagementObjectCollection results = this.getSearchResults(
				targetComputer
				, wmiNamespaceName
				, "Select * from meta_class"
				, out error);

			if (results != null)
			{
				listOfClasses = new List<string>();
				foreach (ManagementClass wmiClass in results)
				{
					foreach (QualifierData qd in wmiClass.Qualifiers)
					{
						// If the class is dynamic or static, add it to the class
						// list on the query tab.
						if (qd.Name.Equals("dynamic") || qd.Name.Equals("static"))
						{
							listOfClasses.Add(wmiClass["__CLASS"].ToString());
						}
					}
				}
				listOfClasses.Sort();
			}

			return listOfClasses;
		}

		private List<string> getWmiClassProperties(
			string targetComputer
			, string wmiNamespaceName
			, string wmiClassName)
		{
			Exception error = null;
			List<string> classProperties = null;
			ManagementScope ms = this.getManagementScope(targetComputer, wmiNamespaceName, out error);

			if (ms != null)
			{
				ManagementClass mc = new ManagementClass(ms
					, new ManagementPath(wmiNamespaceName), _objectGetOptions);
				PropertyDataCollection pdc = mc.Properties;

				classProperties = new List<string>();
				foreach (PropertyData dataObject in pdc)
				{
					classProperties.Add(dataObject.Name);
				}
				classProperties.Sort();
			}

			return classProperties;
		}

		private DataTable getWmiClassPropertiesAndDataTypes(
			string targetComputer
			, string wmiNamespaceName
			, string wmiClassName)
		{
			Exception error = null;
			DataTable classProperties = null;

			ManagementScope ms = this.getManagementScope(targetComputer, wmiNamespaceName, out error);

			if (ms != null)
			{
				ManagementClass mc = new ManagementClass(ms
					, new ManagementPath(wmiNamespaceName), _objectGetOptions);
				PropertyDataCollection pdc = mc.Properties;

				classProperties = new DataTable();
				classProperties.Columns.Add("Name");
				classProperties.Columns.Add("Data Type");
				foreach (PropertyData dataObject in pdc)
				{
					DataRow dr = classProperties.NewRow();
					dr["Name"] = dataObject.Name;
					dr["Data Type"] = dataObject.Type.ToString();
					classProperties.Rows.Add(dr);
				}
			}

			return classProperties;
		}

		private DataTable getWmiData(
			string targetComputer
			, string wmiNamespaceName
			, string wmiQueryLanguage)
		{

			DataTable wmiData = new DataTable();
			wmiData.Columns.Add(COLUMN_NAME_COMPUTER_NAME, Type.GetType("System.String"));
			wmiData.Columns.Add(COLUMN_NAME_ERROR, Type.GetType("System.String"));
			wmiData.Columns.Add(COLUMN_NAME_EXCEPTION_TYPE, Type.GetType("System.String"));

			Exception errorResults;
			ManagementObjectCollection results =
				this.getSearchResults(targetComputer, wmiNamespaceName, wmiQueryLanguage, out errorResults);

			if (results != null)
			{
				int count = 0;
				foreach (ManagementObject queryObj in results)
				{
					count++;
					DataRow currentData = wmiData.NewRow();
					currentData[COLUMN_NAME_COMPUTER_NAME] = targetComputer;
					copyDataFromWmiQueryResultsToDataTable(queryObj.Properties, ref wmiData, ref currentData);
					wmiData.Rows.Add(currentData);
				}

				if (count == 0)
				{
					DataRow currentData = wmiData.NewRow();
					currentData[COLUMN_NAME_COMPUTER_NAME] = targetComputer;
					currentData[COLUMN_NAME_ERROR] = "No results returned.";
					wmiData.Rows.Add(currentData);
				}
			}
			else
			{
				DataRow currentData = wmiData.NewRow();
				currentData[COLUMN_NAME_COMPUTER_NAME] = targetComputer;
				currentData[COLUMN_NAME_ERROR] = errorResults.Message;
				if (errorResults.InnerException != null)
				{
					currentData[COLUMN_NAME_ERROR] +=
						"\n" + errorResults.InnerException.Message;
				}
				currentData[COLUMN_NAME_EXCEPTION_TYPE] = errorResults.GetType().ToString();
				wmiData.Rows.Add(currentData);
			}

			return wmiData;
		}

		private DataTable getWmiData(
			string targetComputer
			, string wmiNamespaceName
			, string wmiClassName
			, List<string> wmiClassProperties)
		{
			return this.getWmiData(targetComputer, wmiNamespaceName, buildWqlQuery(wmiClassName, wmiClassProperties));
		}

		private void copyDataFromWmiQueryResultsToDataTable(
			PropertyDataCollection pdc
			, ref DataTable formattedDataTable
			, ref DataRow rowToCopyDataInto)
		{
			foreach (PropertyData pd in pdc)
			{
				//if (!formattedDataTable.Columns.Contains(pd.Name.ToUpperInvariant()))
				//{
				//    buildAndCheckColumns(pd, ref formattedDataTable);
				//}

				if (pd.Value != null)
				{
					if (!pd.IsArray)
					{
						if (pd.Type == CimType.DateTime)
						{
							try
							{
								rowToCopyDataInto[pd.Name.ToUpperInvariant()] =
									ManagementDateTimeConverter.ToDateTime(pd.Value.ToString()).ToUniversalTime();
							}
							catch (ArgumentException)
							{
								formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), translateCimEnumerationToSystemType(pd.Type));
								formattedDataTable.Columns[pd.Name.ToUpperInvariant()].Caption = pd.Name;	//Store the nicely capitalized name
								rowToCopyDataInto[pd.Name.ToUpperInvariant()] =
									ManagementDateTimeConverter.ToDateTime(pd.Value.ToString()).ToUniversalTime();
							}
						}
						else if (pd.Type == CimType.Reference)
						{
							try
							{
								rowToCopyDataInto[pd.Name.ToUpperInvariant()] = pd.Value;
							}
							catch (ArgumentException)
							{
								formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), translateCimEnumerationToSystemType(pd.Type));
								formattedDataTable.Columns[pd.Name.ToUpperInvariant()].Caption = pd.Name;	//Store the nicely capitalized name
								rowToCopyDataInto[pd.Name.ToUpperInvariant()] = pd.Value;
							}
							//ManagementObject references = this.getSpecificObject(pd.Value.ToString(), out error);
							//buildAndCheckColumns(references.Properties, ref formattedDataTable);
							//copyDataFromWmiQueryResultsToDataTable(
							//    references.Properties
							//    , ref formattedDataTable
							//    , ref rowToCopyDataInto);
						}
						else
						{
							try
							{
								rowToCopyDataInto[pd.Name.ToUpperInvariant()] = pd.Value;
							}
							catch (ArgumentException)
							{
								formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), translateCimEnumerationToSystemType(pd.Type));
								formattedDataTable.Columns[pd.Name.ToUpperInvariant()].Caption = pd.Name;	//Store the nicely capitalized name
								rowToCopyDataInto[pd.Name.ToUpperInvariant()] = pd.Value;
							}
						}
						//Deprecated
						//catch (ArgumentException ex)
						//{
						//    rowToCopyDataInto[COLUMN_NAME_ERROR] = "Error storing value:\n\r" + ex.Message;
						//    rowToCopyDataInto[COLUMN_NAME_EXCEPTION_TYPE] = ex.GetType().ToString();
						//}
					}
					else
					{
						try
						{
							StringBuilder sb = new StringBuilder();

							foreach (object o in (Array)pd.Value)
							{
								if (o != null)
								{
									sb.Append(o.ToString());
								}
								else
								{
									sb.Append(string.Empty);
								}
								sb.Append(",");
							}
							//Remove the last comma seperator
							sb.Remove(sb.Length - 1, 1);
						}
						catch (ArgumentException)
						{
							formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), Type.GetType("System.String"));
							formattedDataTable.Columns[pd.Name.ToUpperInvariant()].Caption = pd.Name;	//Store the nicely capitalized name
							//TODO: ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/fxref_system.data/html/9353dda3-def5-c9b6-121d-4dff0d6a275c.htm

							StringBuilder sb = new StringBuilder();

							foreach (object o in (Array)pd.Value)
							{
								if (o != null)
								{
									sb.Append(o.ToString());
								}
								else
								{
									sb.Append(string.Empty);
								}
								sb.Append(",");
							}
							//Remove the last comma seperator
							sb.Remove(sb.Length - 1, 1);
						}
					}
				}
				else
				{
					try
					{
						rowToCopyDataInto[pd.Name.ToUpperInvariant()] = DBNull.Value;
					}
					catch (ArgumentException)
					{
						formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), translateCimEnumerationToSystemType(pd.Type));
						formattedDataTable.Columns[pd.Name.ToUpperInvariant()].Caption = pd.Name;	//Store the nicely capitalized name
						rowToCopyDataInto[pd.Name.ToUpperInvariant()] = DBNull.Value;
					}
				}
			}
		}

		//private void buildAndCheckColumns(PropertyData pd, ref DataTable formattedDataTable)
		//{
		//    //Consistently case column names so we don't run into case sensitive matching issues later.
		//    if (!formattedDataTable.Columns.Contains(pd.Name.ToUpperInvariant()))
		//    {
		//        if (!pd.IsArray)
		//        {
		//            formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), translateCimEnumerationToSystemType(pd.Type));
		//        }
		//        else
		//        {
		//            formattedDataTable.Columns.Add(pd.Name.ToUpperInvariant(), Type.GetType("System.String"));
		//            //TODO: ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/fxref_system.data/html/9353dda3-def5-c9b6-121d-4dff0d6a275c.htm
		//        }
		//    }
		//    //Store the nicely capitalized name
		//    formattedDataTable.Columns[pd.Name.ToUpperInvariant()].Caption = pd.Name;
		//}

		private string buildWqlQuery(string wmiClassName, List<string> wmiClassProperties)
		{
			StringBuilder sbWqlQuery = new StringBuilder(20 * wmiClassName.Length);	//assume average property name size ~20.
			sbWqlQuery.Append("SELECT ");
			foreach (string s in wmiClassProperties)
			{
				sbWqlQuery.Append(s);
				sbWqlQuery.Append(",");
			}
			//Remove the last comma seperator
			sbWqlQuery.Remove(sbWqlQuery.Length - 1, 1);
			sbWqlQuery.Append(" FROM ");
			sbWqlQuery.Append(wmiClassName);
			return sbWqlQuery.ToString();
		}

		private Type translateCimEnumerationToSystemType(CimType wmiType)
		{
			Type translatedCim = null;
			switch (wmiType)
			{
				case CimType.Boolean:
					translatedCim = typeof(Boolean);
					break;
				case CimType.Char16:
					translatedCim = typeof(Char);
					break;
				case CimType.DateTime:
					translatedCim = typeof(DateTime);
					break;
				case CimType.None:
					translatedCim = null;
					break;
				case CimType.Object:
					translatedCim = typeof(Object);
					break;
				case CimType.Real32:
					translatedCim = typeof(Single);
					break;
				case CimType.Real64:
					translatedCim = typeof(Double);
					break;
				case CimType.Reference:
					translatedCim = typeof(String);
					//translatedCim = typeof(Int16);
					break;
				case CimType.SInt16:
					translatedCim = typeof(Int16);
					break;
				case CimType.SInt32:
					translatedCim = typeof(Int32);
					break;
				case CimType.SInt64:
					translatedCim = typeof(Int64);
					break;
				case CimType.SInt8:
					translatedCim = typeof(SByte);
					break;
				case CimType.String:
					translatedCim = typeof(String);
					break;
				case CimType.UInt16:
					translatedCim = typeof(UInt16);
					break;
				case CimType.UInt32:
					translatedCim = typeof(UInt32);
					break;
				case CimType.UInt64:
					translatedCim = typeof(UInt64);
					break;
				case CimType.UInt8:
					translatedCim = typeof(Byte);
					break;
				default:
					translatedCim = null;
					break;
			}
			return translatedCim;
		}
		#endregion
	}
}
